﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace ResistorMoudel
{
    public delegate void SettingChangedHandle(string name, string addresss, string oldvalue, string newvalue);
    [Serializable]
    public struct NewSerialPortSetting
    {
        public string _port;
        public int _baudrate;
        public Parity _parity;
        public int _databit;
        public StopBits _stopbit;
    }

    [ToolboxItem(false)]
    public partial class NewSerialPortWeight : UserControl, ICommunication
    {
        private bool rtsEnable=false;

        public bool RtsEnable
        {
            get { return rtsEnable; }
            set { rtsEnable = value; }
        }


        protected string allReceivedString;
        public static List<NewSerialPortWeight> NewSerialPortList = new List<NewSerialPortWeight>();
        private SerialPort SerialPort;
        AutoResetEvent resetevent = new AutoResetEvent(false);
        private NewSerialPortSetting _setting;
        string ContempData = "";
        public event Action<string> OnReceiveData;
        public bool IsFormShowType = false;
        public static event SettingChangedHandle SettingChanged;
        private DateTime lastreceiveddatetime;

        public DateTime LastDateTime
        {
            get
            {
                return lastreceiveddatetime;
            }
            set
            {
                lastreceiveddatetime = value;
            }
        }

        public string AllReceivedString
        {
            get
            {
                return allReceivedString;
            }
            set
            {
                allReceivedString = value;
                if (allReceivedString.Length > 99999)
                {
                    allReceivedString.Remove(0, allReceivedString.Length - 99999);
                }
            }
        }

        public NewSerialPortSetting Setting
        {
            get
            {
                return _setting;
            }
            set
            {
                string oldvalue = NewSerialPortSettingToString(_setting);
                string newvalue = NewSerialPortSettingToString(value);
                if (oldvalue == newvalue)
                    return;
                SettingChanged?.Invoke($"{Name}串口配置", Name, oldvalue, newvalue);
                _setting = value;
            }
        }

        private string NewSerialPortSettingToString(NewSerialPortSetting newSerialPortSetting )
        {
            string ret = $"端口{newSerialPortSetting._port}波特率{newSerialPortSetting._baudrate}校验位{newSerialPortSetting._parity}数据位{newSerialPortSetting._databit}停止位{newSerialPortSetting._stopbit}";
            return ret;
        }

        public bool IsOpen
        {
            get
            {
                if (SerialPort == null)
                    return false;
                return SerialPort.IsOpen;
            }
        }

        public NewSerialPortWeight()
        {
            InitializeComponent();
            NewSerialPortList.Add(this);
        }

        //从本地导入串口配置
        public NewSerialPortWeight(string name)
        {
            InitializeComponent();

            Name = name;
            try
            {
                Setting = (NewSerialPortSetting)ReadBinF(Name);
            }
            catch
            {
                MessageBox.Show(Name + "--串口配置失败");
                _setting = new NewSerialPortSetting();
                _setting._port = "COM1";
                _setting._baudrate = 9600;
                _setting._databit = 7;
                _setting._stopbit = StopBits.One;
                _setting._parity = Parity.Even;
            }
            SerialPort _serialPort = new SerialPort(Setting._port, Setting._baudrate, Setting._parity, Setting._databit, Setting._stopbit); _serialPort.RtsEnable = RtsEnable;
            _serialPort.RtsEnable = RtsEnable;
            SerialPort = _serialPort;
            //SerialPort.DataReceived += new SerialDataReceivedEventHandler(NewserialPort_DataReceived);
            NewSerialPortList.Add(this);
        }

        public NewSerialPortWeight(string name, bool isFormshownType)
        {
            IsFormShowType = isFormshownType;
            InitializeComponent();
            Name = name;
            try
            {
                Setting = (NewSerialPortSetting)ReadBinF(Name);
            }
            catch
            {
                MessageBox.Show(Name + "--串口配置失败");
                _setting = new NewSerialPortSetting();
                _setting._port = "COM1";
                _setting._baudrate = 9600;
                _setting._databit = 7;
                _setting._stopbit = StopBits.One;
                _setting._parity = Parity.Even;
            }
            SerialPort _serialPort = new SerialPort(Setting._port, Setting._baudrate, Setting._parity, Setting._databit, Setting._stopbit); _serialPort.RtsEnable = RtsEnable;
            SerialPort = _serialPort;
            //SerialPort.DataReceived += new SerialDataReceivedEventHandler(NewserialPort_DataReceived);
            NewSerialPortList.Add(this);
        }

        public NewSerialPortWeight(string _port, int _baudrate, Parity _parity, int _databit, StopBits _stopbit)
        {
            InitializeComponent();
            SerialPort _serialPort = new SerialPort(_port, _baudrate, _parity, _databit, _stopbit); _serialPort.RtsEnable = RtsEnable;
            SerialPort = _serialPort;
            //SerialPort.DataReceived += new SerialDataReceivedEventHandler(NewserialPort_DataReceived);
        }

        public void Open()
        {
            if (SerialPort != null)
            {
                OnReceiveData = null;
                SerialPort.DataReceived -= new SerialDataReceivedEventHandler(NewserialPort_DataReceived);
                SerialPort.Close();
                SerialPort.Dispose();
                SerialPort = null;
            }
            SerialPort _serialPort = new SerialPort(Setting._port, Setting._baudrate, Setting._parity, Setting._databit, Setting._stopbit); _serialPort.RtsEnable = RtsEnable;
            SerialPort = _serialPort;
            try
            {
                SerialPort.Open();

            }
            catch (Exception exp)
            {

            }
            SerialPort.DataReceived -= new SerialDataReceivedEventHandler(NewserialPort_DataReceived);
            SerialPort.DataReceived += new SerialDataReceivedEventHandler(NewserialPort_DataReceived);
        }

        public void Close()
        {
            if (SerialPort != null)
            {
                if (SerialPort.IsOpen)
                {
                    SerialPort.Close();
                    SerialPort.DataReceived -= new SerialDataReceivedEventHandler(NewserialPort_DataReceived);
                }
            }
        }


        public void SendMessage(string sendContent)
        {

            if (!SerialPort.IsOpen)
            {
                return;
            }
            //SerialPort.ReadExisting();  //清除串口数据
            //Thread.Sleep(10);
            SerialPort.Write(sendContent);

        }


        [Obsolete]
        public string SendBackMessageIntime(string sendContent, int millisecondsTimeWait)
        {

            if (millisecondsTimeWait >= 0)
            {
                if (!SerialPort.IsOpen)
                {
                    return null;
                }
                SerialPort.ReadExisting();  //清除串口数据
                Thread.Sleep(10);
                SerialPort.Write(sendContent);
                Thread.Sleep(millisecondsTimeWait);
                ContempData = SerialPort.ReadExisting();
                return ContempData;
            }
            else
            {
                if (!SerialPort.IsOpen)
                {
                    return null;
                }
                SerialPort.ReadExisting();  //清除串口数据
                Thread.Sleep(10);
                return null;
            }

        }


        private void NewserialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            lastreceiveddatetime = DateTime.Now;
            try
            {
                Thread.Sleep(50);
                if (SerialPort == null) return;
                if (SerialPort.IsOpen)
                {
                    // ContempData = SerialPort.ReadTo("\r\n");
                    //while (SerialPort.BytesToRead>0)
                    //{
                        ContempData = SerialPort.ReadExisting();
                        AllReceivedString += ContempData;
                    //}
                   


                    if (!string.IsNullOrEmpty(ContempData))
                    {
                        resetevent.Set();
                        OnReceiveData?.Invoke(ContempData);
                    }
                }
            }
            catch { }
        }


        //超时后返回空值null  参数millisecondsTimeOut<0时，永远等待

        object lock_obj = new object();
        public SendBackResult SendBackMessageInstant(string sendContent, int millisecondsTimeOut)
        {
            lock (lock_obj)
            {

                if (!SerialPort.IsOpen)
                {
                    return SendBackResult.CreateFailure(67, $"{Name}串口没有打开");
                }
                Thread.Sleep(10);
                //string str = SerialPort.ReadExisting();//清除串口数据
                resetevent.Reset();
                Thread.Sleep(20);
                //SerialPort.DataReceived += new SerialDataReceivedEventHandler(NewserialPort_DataReceived);
                try
                {
                    SerialPort.Write(sendContent);
                }
                catch (Exception exp)
                {
                    return SendBackResult.CreateFailure(6133, $"{Name}" + exp.Message);
                }
                if (millisecondsTimeOut >= 0)
                {
                    //resetevent.WaitOne(millisecondsTimeOut);
                    //return ContempData;
                    if (!resetevent.WaitOne(millisecondsTimeOut))
                    {
                        //SerialPort.DataReceived -= new SerialDataReceivedEventHandler(NewserialPort_DataReceived);
                        return SendBackResult.CreateFailure(67, $"{Name}超时");
                    }
                    else
                    {
                        // SerialPort.DataReceived -= new SerialDataReceivedEventHandler(NewserialPort_DataReceived);
                        //ContempData = SerialPort.ReadExisting();
                        return SendBackResult.CreateSuccess(ContempData);
                    }
                }
                else
                {
                    if (!resetevent.WaitOne())
                    {
                        // SerialPort.DataReceived -= new SerialDataReceivedEventHandler(NewserialPort_DataReceived);
                        return SendBackResult.CreateFailure(68, $"{Name}超时");
                    }
                    else
                    {
                        // SerialPort.DataReceived -= new SerialDataReceivedEventHandler(NewserialPort_DataReceived);
                        // ContempData = SerialPort.ReadExisting();
                        return SendBackResult.CreateSuccess(ContempData);
                    }
                }
            }
        }


        enum StopbitM
        {
            One,
            Two,
            OnePointFive
        }



        private void NewSerialPort_Load(object sender, EventArgs e)
        {

            comboBox1.DataSource = SerialPort.GetPortNames();
            comboBox2.SelectedIndex = 5;
            comboBox3.DataSource = Enum.GetNames(typeof(Parity));
            comboBox4.SelectedIndex = 0;
            comboBox5.DataSource = Enum.GetNames(typeof(StopbitM));
            comboBox5.SelectedIndex = 1;
         
            try
            {
                NewSerialPortSetting setting = (NewSerialPortSetting)ReadBinF(this.Name);
                comboBox1.SelectedItem = setting._port;
                comboBox2.SelectedItem = setting._baudrate.ToString();
                comboBox3.SelectedItem = setting._parity.ToString();
                comboBox4.SelectedItem = setting._databit.ToString();
                comboBox5.SelectedItem = setting._stopbit.ToString();
            }
            catch { }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            SaveBinF(Name, Setting);


        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (button2.Text == "打开")
            {
                try
                {
                    _setting._port = comboBox1.Text;
                    _setting._baudrate = int.Parse(comboBox2.Text);
                    _setting._parity = (Parity)Enum.Parse(typeof(Parity), comboBox3.Text);
                    _setting._databit = int.Parse(comboBox4.Text);
                    _setting._stopbit = (StopBits)Enum.Parse(typeof(StopBits), comboBox5.Text);
                    SerialPort _serialPort = new SerialPort(_setting._port, _setting._baudrate, _setting._parity, _setting._databit, _setting._stopbit); _serialPort.RtsEnable = RtsEnable;
                    SerialPort.Close();
                    SerialPort.Dispose();
                    SerialPort = null;
                    SerialPort = _serialPort;
                    SerialPort.Open();
                    if (SerialPort.IsOpen)
                    {
                        label5.BackColor = Color.Red;
                        tableLayoutPanel1.Enabled = false;
                        button2.Text = "关闭";
                        label8.Text = _setting._port;
                    }
                }
                catch (Exception exp)
                {
                    label5.BackColor = Color.Black;
                }
            }
            else
            {
                try
                {
                    Close();
                    label5.BackColor = Color.Black;
                    tableLayoutPanel1.Enabled = true;
                    button2.Text = "打开";
                    label8.Text = _setting._port;
                }
                catch
                {
                    label5.BackColor = Color.Yellow;
                }
            }
        }

        private void label10_Click(object sender, EventArgs e)
        {
            if (!SerialPort.IsOpen)
            {
                return;
            }
            SendMessage(textBox2.Text);
        }

        private void button3_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog fld = new FolderBrowserDialog();
            fld.Description = "选择存放目录";
            if (fld.ShowDialog() == DialogResult.OK)
            {
                string path = fld.SelectedPath;
            }
        }


        private void button3_Click_1(object sender, EventArgs e)
        {
            try
            {
                NewSerialPortSetting newSerialPortSetting = new NewSerialPortSetting();
                newSerialPortSetting._port = comboBox1.Text;
                newSerialPortSetting._baudrate = int.Parse(comboBox2.Text);
                newSerialPortSetting._parity = (Parity)Enum.Parse(typeof(Parity), comboBox3.Text);
                newSerialPortSetting._databit = int.Parse(comboBox4.Text);
                newSerialPortSetting._stopbit = (StopBits)Enum.Parse(typeof(StopBits), comboBox5.Text);
                Setting = newSerialPortSetting;
                SerialPort _serialPort = new SerialPort(Setting._port, Setting._baudrate, Setting._parity, Setting._databit, Setting._stopbit); _serialPort.RtsEnable = RtsEnable;
                SerialPort.Close();
                SerialPort.Dispose();
                SerialPort = null;
                SerialPort = _serialPort;
            }
            catch (Exception exp)
            {
                MessageBox.Show(exp.ToString());
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (IsOpen)
            {
                label5.BackColor = Color.LimeGreen;
                button2.Text = "关闭";
                label8.Text = Setting._port;
                textBox1.Text = ContempData;
            }
            else
            {
                label5.BackColor = Color.Gray;
                button2.Text = "打开";
            }
        }

        private void NewSerialPort_ParentChanged(object sender, EventArgs e)
        {
            if (this.ParentForm != null)
            {
                if (IsFormShowType)
                {
                    ParentForm.FormClosing += new FormClosingEventHandler(ParentForm_FormClosing);
                    ParentForm.AutoSize = true;
                    ParentForm.Text = Name;
                }
                else
                {

                }
                timer1.Start();
            }
            else
            {
                timer1.Stop();
            }
        }


        private void ParentForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            this.ParentForm.Controls.Clear();
        }


        private void button4_Click(object sender, EventArgs e)
        {

        }

        private void SaveBinF(string _name, object _obj)
        {
            lock (lock_binf)
            {
                try
                {
                    string path = "AND_ConfigurationData\\BinFile\\";
                    if (!Directory.Exists(path))
                    {
                        Directory.CreateDirectory(path);
                    }
                    IFormatter formatter = new BinaryFormatter();
                    Stream stream = new FileStream(path + _name + ".bin", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
                    if (_obj == null)
                    {
                        formatter.Serialize(stream, "null");
                        stream.Close();
                        stream.Dispose();
                    }
                    else
                    {
                        formatter.Serialize(stream, _obj);
                        stream.Close();
                        stream.Dispose();
                    }
                }
                catch (Exception ex)
                {
                    throw new Exception(ex.Message);
                }
            }
        }

        private readonly object lock_binf = new object();
        private object ReadBinF(string _name)
        {
            lock (lock_binf)
            {
                try
                {
                    IFormatter formatter = new BinaryFormatter();
                    string path = "AND_ConfigurationData\\BinFile\\";
                    path = path + _name + ".bin";
                    Stream streamc = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.None);
                    object ret = formatter.Deserialize(streamc);
                    streamc.Close();
                    streamc.Dispose();
                    if (ret.ToString() == "null")
                    {
                        return null;
                    }
                    else
                    {
                        return ret;
                    }
                }
                catch (Exception exp)
                {

                    throw new Exception("读取二进制文件" + _name + "失败！" + "错误信息:" + exp.Message);

                }
            }
        }
    }


    public struct SendBackResult
    {
        public bool Success;
        public string Content;
        public int ErrCode;
        public string ErrMsg;

        public static SendBackResult Create(bool success, string content, int errcode, string errmsg)
        {
            SendBackResult sendBackResult = new SendBackResult();
            sendBackResult.Success = success;
            sendBackResult.Content = content;
            sendBackResult.ErrCode = errcode;
            sendBackResult.ErrMsg = errmsg;
            return sendBackResult;
        }

        public static SendBackResult CreateFailure(int errcode, string errmsg)
        {
            return Create(false, null, errcode, errmsg);
        }

        public static SendBackResult CreateSuccess(string content)
        {
            return Create(true, content, 0, "");
        }
    }
}
